#include <stdio.h>  
#include <stdlib.h>  
#include <string.h>  
#include <sys/socket.h>  
#include <netinet/in.h>  
#include <arpa/inet.h>  
#include <unistd.h>  
#include <netdb.h>
  
#define MAX_BUFFER_SIZE 1024  
#define SERVER_PORT 8080  
  
// 处理请求，返回结果
char *controller(char *requestContent);

int main() {  
    int server_socket, client_socket;  
    // 定义了sockaddr_in类型的两个结构体
    struct sockaddr_in server_addr, client_addr;  
    char buffer[MAX_BUFFER_SIZE];  
    char *base_response = "HTTP/1.1 200 OK\r\nContent-Type: text/html; charset=UTF-8\r\n\r\n"; 
    char *http_response;
  
    // 创建 socket  AF_INET地表ipv4，SOCK_STREAM代表TCP,0代表默认值
    server_socket = socket(AF_INET, SOCK_STREAM, 0);  
    if (server_socket == -1) {  
        // 可以把具体的异常打印出来
        perror("socket");  
        exit(EXIT_FAILURE);  
    }  
  
    // 设置服务器地址结构体  
    // 初始化结构体，使用0填充
    memset(&server_addr, 0, sizeof(server_addr));  
    server_addr.sin_family = AF_INET;  
    //htos主要是把端口数字反转，因为网络传输数据是大端顺序，需要做一个反转
    server_addr.sin_port = htons(SERVER_PORT);  
    // INADDR_ANY代表本机0.0.0.0，也就是说本机所有网卡的所有ip都会绑监听
    server_addr.sin_addr.s_addr = INADDR_ANY;  
  
    // 绑定 socket 到端口  
    // 套接字文件描述符、端口号和ip绑定到一起
    if (bind(server_socket, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1) {  
        perror("bind");  
        exit(EXIT_FAILURE);  
    }  
  
    // 监听连接请求  
    if (listen(server_socket, 10) == -1) {  
        perror("listen");  
        exit(EXIT_FAILURE);  
    }  
  
    printf("HTTP server listening on port %d...\n", SERVER_PORT);  
    printf("request url can be '/' or '/ip' or '/close'\n");
  
    while (1) {  
        socklen_t client_addr_len = sizeof(client_addr);  
        client_socket = accept(server_socket, (struct sockaddr *)&client_addr, &client_addr_len);  
        if (client_socket == -1) {  
            perror("accept");  
            continue;  
        }  
        printf("New connection from %s:%d\n", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));  
  
        // 读取客户端请求数据并发送响应数据给客户端  
        int bytes_read = recv(client_socket, buffer, MAX_BUFFER_SIZE, 0);  
        if (bytes_read <= 0) {  
            printf("Connection closed by client.\n");  
            close(client_socket);  
            continue;  
        }  
        buffer[bytes_read] = '\0'; // 在读取数据的末尾添加字符串结束符  
        printf("Received request:\n%s\n", buffer);  
        http_response = controller(buffer);
        // pin jie xiangying jieguo
        char final_response[strlen(base_response)+strlen(http_response)+1];
        strcpy(final_response,base_response);
        strcat(final_response,http_response);
        send(client_socket, final_response, strlen(final_response), 0); // 发送 HTTP 响应给客户端  
        close(client_socket); // 关闭客户端 socket 连接  
    }  
}

// 处理请求，返回结果
char *controller(char *requestContent){
    // 解析出url，也就是解析出开头两个空格之间的内容
    char *spacePtr1= strchr(requestContent,' ');
    char *spacePtr2= strchr(spacePtr1+1,' ');
    int pathLength = spacePtr2-spacePtr1-1;
    char path[pathLength+1]; 
    strncpy(path,spacePtr1+1,pathLength);
    path[pathLength+1]='\0';
    if(strcmp("/", path)==0){
        return "hello world";
    }else if(strcmp("/ip", path)==0){
        struct hostent *host; 
        char hostname[256];  
        gethostname(hostname, sizeof(hostname)); 
        host = gethostbyname(hostname);  
        if (host == NULL) {  
            printf("Failed to get IP address of current server.\n");  
            return "error";
        }else{
             struct in_addr **addr_list_ptr; 
             addr_list_ptr = (struct in_addr **)host->h_addr_list;  
            for (; *addr_list_ptr != NULL; addr_list_ptr++) {
                struct in_addr *addr = *addr_list_ptr;  
                if(strcmp(inet_ntoa(*addr),"127.0.0.1") != 0){
                    return inet_ntoa(*addr);
                }
            } 
            // default value
            return inet_ntoa(*(struct in_addr *)host->h_addr_list[0]);
        }
    }else if(strcmp("/close", path)==0){
        printf("正常退出\n");
        exit(EXIT_SUCCESS);
        
    }else{
        return "can not match request";
    }
}